#pragma once

#include "GameData.h"
#include <QObject>
#include <QGraphicsScene>
#include <QKeyEvent>
#include <map>
#include <set>


#define GAME_SETTING 0
#define GAME_MAP_REC 1
#define GAME_STARTED 2
#define GAME_IN_PROC 3
#define GAME_OVER 4


class IManager : public QObject
{
    Q_OBJECT

public:
    IManager(QGraphicsScene * scene);
    virtual ~IManager();

public slots:
    // Use these two slots to allow a player on this copmuter to control his/her/its tank
    virtual void slotKeyPresEvent(QKeyEvent * event) = 0;
    virtual void slotKeyReleaseEvent(QKeyEvent * event) = 0;

    // Creates a map + initial configurations
    virtual void slotCreateMap(int width, int height, const QString& map, int health, int motion_speed, int bullet_speed, int fire_rate);

    // Call this method to update game configurations to current time
    virtual void slotUpdate() = 0;

    // Call this method to start the game
    // Returns: whether the game started actually
    // Note: can call only after successful CreateMap() and SetNickname()
    virtual void slotStart() = 0;

    // Call this method to fire from the tank with a specified id
    virtual void slotFire(int tank_id) = 0;

    // Call this method to stop firing from the tank with a specified id
    virtual void slotStopFire(int tank_id) = 0;

    // Call this method to move the tank with a specified id
    virtual void slotMove(int tank_id) = 0;

    // Call this method to turn the tank with a specified id
    virtual void slotTurn(int tank_id, char direction) = 0;

    // Call this method to stop motion of the tank with a specified id
    virtual void slotStopMove(int tank_id) = 0;

protected:
    bool testCollisionTank(int tank_id);
    bool testCollisionBullet(int bullet_id, int& tank_id1, int& tank_id2, int bullet_id1);
    bool testNickname(QString& nick);
    void advance(long timestamp, bool& need_snapshot);
    bool demageTank(int tank_id);

    GameData * m_ptr_gameData;
    long m_timestamp;
    int m_update_time;
    int m_motion_speed;
    int m_bullet_speed;
    int m_max_health;
    int m_fire_rate;

    static const int MIN_NICK_LENGTH = 3;
    static const int MAX_NICK_LENGTH = 15;

    QGraphicsScene * m_ptr_scene;

    struct Player
    {
        Player(): action('S'), action_queue(""), firing(false), last_fired(0)
        { }

        bool queueEmpty()
        {
            return action_queue.length() == 0;
        }

        char nextAction()
        {
            if (queueEmpty())
                return action;
            action = action_queue.at(0).toAscii();
            action_queue = action_queue.remove(0, 1);
            return action;
        }

        char action;
        QString action_queue;
        bool firing;
        long last_fired;
    };
    std::map<int, Player> m_players;
    std::set<int> m_erase_bullets;

    int max_bullet;

    int game_status;
};
